package main

import (
	"errors"
	"fmt"
	"gitee.com/MrDaiM/msgo"
	msgLog "gitee.com/MrDaiM/msgo/log"
	"gitee.com/MrDaiM/msgo/mserror"
	"gitee.com/MrDaiM/msgo/mspool"
	"gitee.com/MrDaiM/msgo/token"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"sync"
	"time"
)

type User struct {
	Name      string   `xml:"name" json:"name" msgo:"required"`
	Age       int      `xml:"age" json:"age" validate:"required,max=50,min=18"`
	Addresses []string `json:"addresses"`
	Email     string   `json:"email" msgo:"required"`
}

type UserXML struct {
	Name string `xml:"name" json:"name"`
	Age  int    `xml:"age" json:"age"`
}

func main() {

	//http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
	//	fmt.Fprintln(writer, "hello leon")
	//})
	//
	//err := http.ListenAndServe(":8111", nil)
	//if err != nil {
	//	log.Fatal(err)
	//}

	//engine := msgo.New()
	//engine.Add("/hello", func(w http.ResponseWriter, r *http.Request) {
	//	fmt.Fprintln(w, "hello leon")
	//})
	//engine.Run()

	//engine := msgo.New()
	//g := engine.Group("user")
	//g.Add("/hello", func(w http.ResponseWriter, r *http.Request) {
	//	fmt.Fprintln(w, "hello leon")
	//})

	engine := msgo.Default()
	engine.RegisterErrorHandler(func(err error) (int, any) {
		switch e := err.(type) {
		case *BlogResponse:
			return http.StatusOK, e.Response()
		default:
			return http.StatusInternalServerError, "500 error"

		}
	})
	//// ===这一步需要再注册的时候使用
	//// 先生成base64
	//fmt.Println(msgo.BasicAuth("leon", "123456"))
	//auth := &msgo.Accounts{
	//	Users: make(map[string]string),
	//}
	//auth.Users["leon"] = "123456"
	//// ===========
	//
	//// 使用框架提供的认证
	//engine.Use(auth.BasicAuth)

	jh := token.JwtHandler{Key: []byte("123456")}
	engine.Use(jh.AuthInterceptor)

	g := engine.Group("user")
	//g.Use(msgo.Logging)
	//g.Use(msgo.Logging, msgo.Recovery)
	g.Use(func(next msgo.HandlerFunc) msgo.HandlerFunc {
		return func(ctx *msgo.Context) {
			fmt.Println("pre handler")
			next(ctx)
			fmt.Println("post handler")

		}
	})
	//g.PostHandle(func(handlerFunc msgo.HandlerFunc) msgo.HandlerFunc {
	//	return func(ctx *msgo.Context) {
	//		fmt.Println("post handler")
	//	}
	//})

	//g.Get("/hello/get", func(ctx *msgo.Context) {
	//	fmt.Println("handler")
	//	fmt.Fprintln(ctx.W, "hello leon2")
	//}, Log)

	g.Get("/html", func(ctx *msgo.Context) {
		fmt.Println("hello leon")
		ctx.HTML(http.StatusOK, "<h1>leon</h1>")
	})

	g.Get("/htmlTemplate", func(ctx *msgo.Context) {
		fmt.Println("hello leon")
		user := &User{
			Name: "leon",
		}
		err := ctx.HTMLTemplate("login.html", template.FuncMap{}, user, "tpl/login.html", "tpl/header.html")
		if err != nil {
			log.Println(err)
		}
	})

	g.Get("/htmlTemplateGlob", func(ctx *msgo.Context) {
		fmt.Println("hello leon")
		user := &User{
			Name: "leon",
		}
		err := ctx.HTMLTemplateGlob("login.html", user, "tpl/*.html")
		if err != nil {
			log.Println(err)
		}
	})

	// 提前加载模版到内存
	engine.LoadTemplate("tpl/*.html")
	g.Get("/template", func(ctx *msgo.Context) {
		user := &User{
			Name: "web 框架",
		}
		err := ctx.Template("login.html", user)

		if err != nil {
			log.Println(err)
		}
	})

	g.Get("/userInfo", func(ctx *msgo.Context) {
		_ = ctx.JSON(http.StatusOK, &User{
			Name: "go微服务框架",
		})
	})

	g.Get("/json", func(ctx *msgo.Context) {
		_ = ctx.JSON(http.StatusOK, &User{
			Name: "go微服务框架",
		})
	})

	g.Get("/hello", func(ctx *msgo.Context) {
		_ = ctx.JSON(http.StatusOK, &User{
			Name: "hello go微服务框架",
		})
	})

	g.Get("/xml", func(ctx *msgo.Context) {
		user := &UserXML{
			Name: "go 微服务框架",
			Age:  10,
		}
		_ = ctx.XML(http.StatusOK, user)
	})

	// 下载文件
	g.Get("/excel", func(ctx *msgo.Context) {
		ctx.File("tpl/test.xlsx")
	})

	// 下载文件指定文件名
	g.Get("/excelName", func(ctx *msgo.Context) {
		ctx.FileAttachment("tpl/test.xlsx", "abc.xlsx")
	})

	// 从文件系统下载
	g.Get("/fs", func(ctx *msgo.Context) {
		ctx.FileFromFS("test.xlsx", http.Dir("tpl"))
	})

	// 重定向
	g.Get("/toRedirect", func(ctx *msgo.Context) {
		ctx.Redirect(http.StatusFound, "/user/hello")
	})

	// 字符串
	g.Get("/string", func(ctx *msgo.Context) {
		query := ctx.GetQuery("id")
		values := ctx.QueryArray("id")
		fmt.Println(values)
		ctx.String(http.StatusOK, "%s 是由 %s 制作 \n", "goweb框架", query)
	})

	g.Get("/string2", func(ctx *msgo.Context) {
		ctx.String(http.StatusOK, "leon....")
	})

	// http://127.0.0.1:8111/user/add?id=100
	g.Get("/add", func(ctx *msgo.Context) {
		query := ctx.GetQuery("id")
		_, _ = fmt.Fprintf(ctx.W, "id:%s\n", query)
	})

	// http://127.0.0.1:8111/user/add?id=100&id=102
	g.Get("/add2", func(ctx *msgo.Context) {
		query := ctx.QueryArray("id")
		_, _ = fmt.Fprintf(ctx.W, "id:%v\n", query)
	})

	g.Get("/add3", func(ctx *msgo.Context) {
		query := ctx.DefaultQuery("name", "张三")
		_, _ = fmt.Fprintf(ctx.W, "id:%v\n", query)
	})

	// http://127.0.0.1:8111/user/queryMap?user[id]=1&user[name]=%E5%BC%A0%E4%B8%89
	g.Get("/queryMap", func(ctx *msgo.Context) {
		dicts := ctx.QueryMap("user")
		_, _ = fmt.Fprintf(ctx.W, "id:%v\n", dicts)
	})

	g.Post("/formPost", func(ctx *msgo.Context) {
		m, _ := ctx.GetPostFormArray("name")
		ctx.JSON(http.StatusOK, m)
	})

	g.Post("/formPostFile", func(ctx *msgo.Context) {
		m, _ := ctx.GetPostFormMap("user")
		file, err := ctx.FormFile("file")
		if err != nil {
			log.Println(err)
		}

		src, err := file.Open()
		if err != nil {
			log.Println(err)
			return
		}

		// 创建文件
		dst, err := os.Create("./upload/" + file.Filename)
		if err != nil {
			log.Println(err)
			return
		}
		_, _ = io.Copy(dst, src)
		ctx.JSON(http.StatusOK, m)
	})

	g.Post("/formPostFile2", func(ctx *msgo.Context) {
		m, _ := ctx.GetPostFormMap("user")
		file, err := ctx.FormFile("file")
		if err != nil {
			log.Println(err)
		}
		var dst = "./upload/" + file.Filename
		err = ctx.SaveUploadFile(file, dst)

		if err != nil {
			log.Println(err)
			return
		}
		ctx.JSON(http.StatusOK, m)
	})
	// 上传多个文件
	g.Post("/formPostFile3", func(ctx *msgo.Context) {
		m, _ := ctx.GetPostFormMap("user")

		form, err := ctx.MultipartForm()
		log.Println(err)

		fileMap := form.File
		headers := fileMap["file"]
		for _, file := range headers {
			ctx.SaveUploadFile(file, "./upload/"+file.Filename)
		}

		ctx.JSON(http.StatusOK, m)
	})

	// 上传多个文件
	g.Post("/formPostFile4", func(ctx *msgo.Context) {
		m, _ := ctx.GetPostFormMap("user")

		files := ctx.FormFiles("file")
		for _, file := range files {
			ctx.SaveUploadFile(file, "./upload/"+file.Filename)
		}
		ctx.JSON(http.StatusOK, m)
	})

	// Json 参数
	g.Post("/jsonParam", func(ctx *msgo.Context) {
		user := &User{}
		ctx.DisallowUnknownFields = true
		ctx.IsValidate = true
		err := ctx.BindJson(user)
		if err == nil {
			ctx.JSON(http.StatusOK, user)
		} else {
			log.Println(err)
		}
	})

	g.Post("/jsonParamList", func(ctx *msgo.Context) {
		users := make([]User, 0)
		ctx.DisallowUnknownFields = true
		ctx.IsValidate = true
		err := ctx.BindJson(&users)
		if err == nil {
			ctx.JSON(http.StatusOK, users)
		} else {
			log.Println(err)
		}
	})

	//logger := msgLog.Default()
	engine.Logger.Level = msgLog.LevelDebug
	// 更改 formatter
	//engine.Logger.Formatter = &msgLog.JsonFormatter{
	//	TimeDisplay: true,
	//}
	// 写入文件(提供一个方法进行设置)
	//logger.Outs = append(logger.Outs, msgLog.FileWriter("./log/log.log"))
	engine.Logger.SetLogPath("./log")
	engine.Logger.LogFileSize = 1 << 10 // 1k
	var u *User
	g.Post("/xmlParam2", func(ctx *msgo.Context) {
		u.Age = 10
		user := &User{}
		err := ctx.BindXML(user)
		if err == nil {

			ctx.Logger.WithFields(msgLog.Fields{
				"name": "leon",
				"id":   100,
			}).Debug("我是debug日志")
			ctx.Logger.Info("我是info日志")
			ctx.Logger.Error("我是error日志")

			ctx.JSON(http.StatusOK, user)
		} else {
			log.Println(err)
		}
	})

	g.Post("/xmlParam3", func(ctx *msgo.Context) {

		user := &User{}
		_ = ctx.BindXML(user)

		// 优雅的处理错误
		err := mserror.Default()
		err.Result(func(msError *mserror.MsError) {
			ctx.Logger.Info(msError.Error())
			_ = ctx.JSON(http.StatusInternalServerError, user) // 发生错误后就不会再往下继续执行了
		})
		a(1, err)
		b(1, err)

		_ = ctx.JSON(http.StatusOK, user)
	})

	g.Post("/xmlParam4", func(ctx *msgo.Context) {
		user := &User{}
		_ = ctx.BindXML(user)

		err := login()
		ctx.HandleWithError(http.StatusOK, user, err)
	})

	p, _ := mspool.NewPool(5)
	g.Post("/pool", func(ctx *msgo.Context) {
		currentTime := time.Now().UnixMilli()
		var wg sync.WaitGroup
		wg.Add(5)
		_ = p.Submit(func() {
			defer func() {
				wg.Done()
			}()
			fmt.Println("11111111111111")
			//panic("出错了")
			time.Sleep(3 * time.Second)

		})
		_ = p.Submit(func() {
			fmt.Println("2222222222222")
			time.Sleep(3 * time.Second)
			wg.Done()
		})
		_ = p.Submit(func() {
			fmt.Println("3333333333333")
			time.Sleep(3 * time.Second)
			wg.Done()
		})
		_ = p.Submit(func() {
			fmt.Println("44444444444444")
			time.Sleep(3 * time.Second)
			wg.Done()
		})
		_ = p.Submit(func() {
			fmt.Println("555555555555555")
			time.Sleep(3 * time.Second)
			wg.Done()
		})
		wg.Wait()
		fmt.Printf("time:%v \n", time.Now().UnixMilli()-currentTime)
		_ = ctx.JSON(http.StatusOK, "success")
	})

	g.Get("/login", func(ctx *msgo.Context) {

		jwt := &token.JwtHandler{}
		jwt.Key = []byte("123456")
		jwt.SendCookie = true
		jwt.TimeOut = 10 * time.Minute
		jwt.RefreshTimeOut = 20 * time.Minute
		jwt.Authenticator = func(ctx *msgo.Context) (map[string]any, error) {
			data := make(map[string]any)
			data["userId"] = 1
			return data, nil
		}
		token, err := jwt.LoginHandler(ctx)
		if err != nil {
			log.Println(err)
			ctx.JSON(http.StatusOK, err.Error())
			return
		}
		ctx.JSON(http.StatusOK, token)
	})
	g.Get("/refresh", func(ctx *msgo.Context) {

		jwt := &token.JwtHandler{}
		jwt.Key = []byte("123456")
		jwt.SendCookie = true
		jwt.TimeOut = 10 * time.Minute
		jwt.RefreshTimeOut = 20 * time.Minute

		jwt.RefreshKey = "blog_refresh_token"
		ctx.Set(jwt.RefreshKey, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTA2NjUzMjMsImlhdCI6MTcxMDY2NDEyMywidXNlcklkIjoxfQ.nc6NL_3O4M2LbTCdJVcY1qIqdvS2FTm-W4_g6fbCJvY")
		token, err := jwt.RefreshHandler(ctx)
		if err != nil {
			log.Println(err)
			ctx.JSON(http.StatusOK, err.Error())
			return
		}
		ctx.JSON(http.StatusOK, token)
	})
	//engine.Run()

	engine.RunTLS(":8118", "key/server.pem", "key/server.key")
}

type BlogResponse struct {
	Success bool
	Code    int
	Data    any
	Msg     string
}

type BlogNoDataResponse struct {
	Success bool
	Code    int
	Msg     string
}

func (b *BlogResponse) Error() string {
	return b.Msg
}

func (b *BlogResponse) Response() any {
	if b.Data == nil {
		return &BlogNoDataResponse{
			Success: false,
			Code:    -999,
			Msg:     "账号密码错误",
		}
	}
	return b
}

func login() *BlogResponse {
	return &BlogResponse{
		Success: false,
		Code:    -999,
		Data:    nil,
		Msg:     "账号密码错误",
	}
}

func a(param int, msError *mserror.MsError) {
	if param == 1 {
		// 发生错误的时候，放入一个地方， 然后进行统一处理
		err := errors.New("a发生错误")
		msError.Put(err)
	}
}

func b(param int, msError *mserror.MsError) {
	if param == 1 {
		// 发生错误的时候，放入一个地方， 然后进行统一处理
		err := errors.New("b发生错误")
		msError.Put(err)
	}
}

func Log(next msgo.HandlerFunc) msgo.HandlerFunc {
	return func(ctx *msgo.Context) {
		fmt.Println("打印请求参数")
		next(ctx)
		fmt.Println("返回执行时间")
	}
}
